<?php

m2import('base/templateEngine/BuildModes.php');
m2import('base/templateEngine/CMSDocument.php');
m2import('cms/elements.o.inc.php');

/**
 * CMS Document Context
 *
 * @author Marcel Linnenfelser
 * @package
 * @since 12.11.2009
 * @license XICS License
 */
class base_templateEngine_DocumentContext {

    /**
     *
     * @var base_templateEngine_CMSTemplate Template object
     */
    private $template = null;
    /**
     *
     * @var string Medium
     */
    private $medium = '';
    /**
     * ID of the document
     * @var int
     */
    private $doc_id = 0;
    /**
     * Fallback value, if doc not loaded (buildMode==cachehit)
     * set in setBuildMode
     * @var int Site id
     */
    private $siteId = 0;
    /**
     * BuildMode
     * @var string
     */
    private $buildMode = '';
    /**
     * Unmasked BuildMode (e.g. cachehit is maskes as cache)
     * @var string
     */
    private $unmaskedBuildMode = '';
    /**
     *
     * @var array Array with env fields to be used in templates and apps
     */
    private $envFields = array();
    /**
     * Array of all languages the document is published in
     * @var array Published languages of document
     */
    private $pubLanguages = array();

    /**
     *
     * @param int $doc_id Doc ID
     * @param mixed $lang Language ID or array with indexes 'id' and 'name' for language
     * @param base_templateEngine_DocumentContext $parent Parent context (doc context hierarchiy represents inclusion hierarchy of documents)
     * @param string $template Template to use to render document
     * @param string $buildMode BuildMode
     * @param string $medium Medium
     */
    public function __construct($doc_id, $lang, base_templateEngine_DocumentContext $parent = null, $template = '', $buildMode = '', $medium = '') {
        phpinchains_ApplicationContext::getInstance()->debug('Method DocumentContext::_construct');
        $this->setDocId((int) $doc_id);
        $this->setParent($parent);
        $this->setTemplate($template);
        $this->setMedium($medium);
        $this->init($this->doc_id, $lang, $this->parent_document, $this->template, $this->medium);
        if ($this->isRoot() && $buildMode) {
            $this->setBuildMode($buildMode);
        }
        $this->loadData();
    }

    /**
     *
     * @return int
     */
    public function getDocId() {
        return $this->doc_id;
    }

    /**
     * Get all environment variables for templates an apps as array
     * @return <type>
     */
    public function getEnvFields() {
        return $this->envFields;
    }
    /**
     * Get a single environment variable for templates an apps
     * @param string $name
     * @return string
     */
    public function getEnvField($name) {
        return $this->envFields[$name];
    }
    /**
     * Set environment variables for templates an apps
     * @param array $f
     */
    public function setEnvFields($f) {
        $this->envFields = $f;
    }

    public function setPubLanguages($l) {
        $this->pubLanguages = $l;
    }

    public function getPubLanguages() {
        return $this->pubLanguages;
    }

    /**
     *
     * @param int $id
     */
    public function setDocId($id) {
        $this->doc_id = (int) $id;
    }

    public function getMedium() {
        return $this->medium;
    }

    public function setMedium($medium) {
        $this->medium = $medium;
    }

    /**
     *
     * @param int $doc_id
     * @param int $lang_id
     * @param base_templateEngine_DocumentContext $parent
     */
    private function init($doc_id, $lang, $parent, $template, $medium = '') {
        phpinchains_ApplicationContext::getInstance()->debug('Method DocumentContext::init');
        if ($parent == null) {
            $this->setIsRoot(true);
            $ctx = base_ApplicationContext::getInstance();

            if ($ctx->getUsr()->isAuthenticated()) {
                phpinchains_ApplicationContext::getInstance()->debug('Method DocumentContext::init User authenticated: load permissions');
                $usr = $ctx->getUsr()->exportUserData();
                $dba = $ctx->getAccessFactory()->getInstanceOf(base_AccessFactory::$CMS);
                $this->setCMSPermissions(new cmsPermission($dba->getUserPermissions($this->doc_id, $usr['data']['id'])));
            }
            if (is_array($lang)) {
                phpinchains_ApplicationContext::getInstance()->debug('Method DocumentContext::init Set language from param');
                $this->setLanguage($lang);
            } else {
                phpinchains_ApplicationContext::getInstance()->debug('Method DocumentContext::init set language from DB');
                $language = array();
                $ldba = $ctx->getAccessFactory()->getInstanceOf(base_AccessFactory::$CMSLang);
                $ldba->getLanguage($language, $lang);
                $this->setLanguage($language);
            }
        } else {
            phpinchains_ApplicationContext::getInstance()->debug('Method DocumentContext::init Init called for child context');
            if ($parent->getCMSpermissions()) { 
                $this->setCMSPermissions($parent->getCMSpermissions());
            }
            $this->setLanguage($parent->getLanguage());
            $this->setIsLive($parent->isLive());
            $this->setDocTree($parent->getDocTree());
            $this->setParent($parent);
            $this->setRoot($parent->getRoot());
            if ($parent->isLive()) {
                $this->setBuildMode($parent->getBuildMode());
            } else {
                $this->setBuildMode(base_templateEngine_BuildModes::$PREVIEW);
            }
        }
    }

    public function setTemplate($template) {
        $this->template = $template;
    }

    public function getTemplate($medium) {
        if ($this->template)
            return str_replace('.psp', $medium . '.psp', $this->template);
        else
            return $this->doc->getContentTemplate() . $medium . '.psp';
    }

    public function getHeaderTemplate() {
        return $this->doc->getHeaderTemplate();
    }

    public function getFooterTemplate() {
        return $this->doc->getFooterTemplate();
    }

    /**
     * Permissions
     * @var cmsPermission
     */
    private $permissions = null;

    /**
     *
     * @return cmsPermission
     */
    public function getCMSpermissions() {
        return $this->permissions;
    }

    /**
     *
     * @param cmsPermission $p
     */
    public function setCMSPermissions(cmsPermission $p) {
        $this->permissions = $p;
    }

    /**
     *
     * @return string
     */
    public function getBuildMode() {
        return $this->buildMode;
    }

    /**
     *
     * @return string
     */
    public function getUnmaskedBuildMode() {
        return $this->buildMode;
    }

    /**
     *
     * @param string $b
     */
    public function setBuildMode($b) {
        phpinchains_ApplicationContext::getInstance()->debug('Method DocumentContext::setBuildMode');
        $this->buildMode = $b;

        // init is live
        $this->setIsLive(!in_array($this->getBuildMode(), array(
                    base_templateEngine_BuildModes::$PUBPREVIEW,
                    base_templateEngine_BuildModes::$PREVIEW,
                    base_templateEngine_BuildModes::$EDITOR
                )));

        // init is live
        $this->setIsLiveDB(!in_array($this->getBuildMode(), array(
                    base_templateEngine_BuildModes::$PREVIEW,
                    base_templateEngine_BuildModes::$EDITOR
                )));
    }

    /**
     * Call after buildMode was set to load the data of the document
     */
    public function loadData() {
        phpinchains_ApplicationContext::getInstance()->debug('Method DocumentContext::loadData');
        if (!$this->getBuildMode()) {
            throw new TemplateEngineException(
                    'Build mode not set. Set build mode before calling loadData().',
                    TemplateEngineException::$MISSING_BUILDMODE
            );
        }
        $ctx = base_ApplicationContext::getInstance();
        $dba = null;
        if (!$this->isLiveDB()) {
            phpinchains_ApplicationContext::getInstance()->debug('Method DocumentContext::setBuildMode Document from EditorDB');
            $dba = $ctx->getAccessFactory()->getInstanceOf(base_AccessFactory::$CMS);
//            $doctree = $dba->getDocDescrTreeBySite($this->getLanguage('id'), $this->getSiteId());
            $doctree = $dba->getDocDescrTree($this->getLanguage('id'));
            $doc = new base_templateEngine_CMSDocument($dba->getCompleteDoc($this->getDocId(), $this->getLanguage('id'),
                                    ($this->getBuildMode() == base_templateEngine_BuildModes::$EDITOR ? false : true)));
        } else {
            // do caching only in live site
            if ($this->isLive()) {
                phpinchains_ApplicationContext::getInstance()->debug('Method DocumentContext::setBuildMode Document with cache from LiveDB');
                $cache = new base_templateEngine_Cache(base_templateEngine_Cache::$DATA_DIR);
                $doctreecachekey = base_templateEngine_CacheKeyBuilder::buildDocTreeKey($this->getLanguage('id'), $this->getSiteId());
                // TODO: hier f�r gro�e multisites entscheidbar machen, ob nur doctree der site geladen wird
                if (!$cache->test($doctreecachekey)) {
                    $ctx = base_ApplicationContext::getInstance();
                    $dba = $ctx->getAccessFactory()->getInstanceOf(base_AccessFactory::$CMS);
                    $doctree = $dba->getPubDocDescrTree($this->getLanguage('id'), $this->getSiteId());
                    $cache->save($doctreecachekey, $doctree);
                }
                $doctree = $cache->load($doctreecachekey);
                // Do not load document data from DB if cachehit: deliver from cache
                if ($this->getBuildMode() == base_templateEngine_BuildModes::$CACHEHIT) {
                    $doc = new base_templateEngine_CMSDocument(null);
                } else {
                    if ($dba == null)
                        $dba = $ctx->getAccessFactory()->getInstanceOf(base_AccessFactory::$CMS);
                    $doc = new base_templateEngine_CMSDocument($dba->getCompletePubDoc($this->getDocId(), $this->getLanguage('id')));
                }
            // if not live site (page displayed in cms) don't do caching
            } else {
                phpinchains_ApplicationContext::getInstance()->debug('Method DocumentContext::setBuildMode Document without from LiveDB');
                $dba = $ctx->getAccessFactory()->getInstanceOf(base_AccessFactory::$CMS);
                $doctree = $dba->getPubDocDescrTree($this->getLanguage('id'), $this->getSiteId());
                $doc = new base_templateEngine_CMSDocument($dba->getCompletePubDoc($this->getDocId(), $this->getLanguage('id')));
            }
        }
        $this->setDocTree(new elements($doctree));
        if ($this->getBuildMode() == base_templateEngine_BuildModes::$CACHEHIT) { // for further processing change to buildMode cache
            phpinchains_ApplicationContext::getInstance()->debug('Method DocumentContext::setBuildMode Set document in cachehit mode');
            $this->setDoc($doc);
        } else { // bei nicht-cachehit doc geladen zum processing
            if ($doc == null || !$doc->getElements())
                throw new TemplateEngineException(
                        'Error loading Document with id ' . $this->getDocId(),
                        TemplateEngineException::$DOCUMENT_NOT_FOUND
                );
            $this->setDoc($doc);
        }
    }

    /**
     * Language
     * @var array
     */
    private $lang = null;

    /**
     *
     * @param  string Name of the language field ('name' or 'id')
     * @return int
     */
    public function getLanguage($field = '') {
        if ($field)
            return $this->lang[$field];
        return $this->lang;
    }

    /**
     *
     * @param int $l
     */
    public function setLanguage($l) {
        $this->lang = $l;
    }

    /**
     * is live
     * @var bool
     */
    private $is_live = null;

    /**
     * Render live: not editor, preview, pubpreview
     * @return bool
     */
    public function isLive() {
        return $this->is_live;
    }

    /**
     *
     * @param bool $l
     */
    public function setIsLive($l) {
        $this->is_live = $l;
    }

    /**
     * use live data
     * @var bool
     */
    private $is_live_db = null;

    /**
     * Render live data: not editor or preview
     * @return bool
     */
    public function isLiveDB() {
        return $this->is_live_db;
    }

    /**
     *
     * @param bool $l
     */
    public function setIsLiveDB($l) {
        $this->is_live_db = $l;
    }
    
    /**
     * CMS Document Data
     * @var base_templateEngine_CMSDocument
     */
    private $doc = null;

    /**
     *
     * @return base_templateEngine_CMSDocument
     */
    public function getDoc() {
        return $this->doc;
    }

    /**
     *
     * @param base_templateEngine_CMSDocument $d
     */
    public function setDoc($d) {
        $this->doc = $d;
    }

    public function getSiteId() {
        if ($this->doc != null && $this->doc->getSiteId()) {
            phpinchains_ApplicationContext::getInstance()->debug('Method DocumentContext::getSiteId From nested doc: '.$this->doc->getSiteId());
            return $this->doc->getSiteId();
        }
        // if buildMode == cachehit doc will not be loaded => site id only set in context
        // set in setBuildMode
        phpinchains_ApplicationContext::getInstance()->debug('Method DocumentContext::getSiteId From property: '.$this->siteId);
        return $this->siteId;
    }

    /**
     * Set Site id manually: used in 
     */
    public function setSiteId($siteId) {
        phpinchains_ApplicationContext::getInstance()->debug('Method DocumentContext::setSiteId Site id: '.$siteId);
        $this->siteId = $siteId;
    }
    
    /**
     * CMS Document Tree
     * @var elements
     */
    private $doc_elements = null;

    /**
     *
     * @return elements
     */
    public function getDocTree() {
        return $this->doc_elements;
    }

    /**
     *
     * @param elements $e
     */
    public function setDocTree($e) {
        $this->doc_elements = $e;
    }

    /**
     * Root Document Context
     *
     * Root document of nested documents
     *
     * @var base_templateEngine_DocumentContext
     */
    private $root_document = null;

    /**
     *
     * @return base_templateEngine_DocumentContext
     */
    public function getRoot() {
        if ($this->isRoot())
            return $this;
        return $this->root_document;
    }

    /**
     *
     * @param base_templateEngine_DocumentContext $r
     */
    public function setRoot($r) {
        // TODO throw Exception on isRoot
        $this->root_document = $r;
    }

    /**
     * Parent Document Context
     *
     * Parent document of nested documents
     *
     * @var base_templateEngine_DocumentContext
     */
    private $parent_document = null;

    /**
     *
     * @return base_templateEngine_DocumentContext
     */
    public function getParent() {
        return $this->parent_document;
    }

    /**
     *
     * @param base_templateEngine_DocumentContext $p
     */
    public function setParent($p) {
        if ($p != null) {
            $this->setIsRoot(false);
            $this->parent_document = $p;
        }
    }

    /**
     * Is root
     *
     * @var bool
     */
    private $is_root = false;

    /**
     *
     * @return bool
     */
    public function isRoot() {
        return $this->is_root;
    }

    /**
     *
     * @param bool $r
     */
    public function setIsRoot($r) {
        $this->is_root = $r;
    }

    /**
     * Create a document index for a nested document
     * @param int $id Document id of the nested document
     */
    public function createChildDocumentContext($id, $template = '') {
        phpinchains_ApplicationContext::getInstance()->debug('Method DocumentContext::createChildDocumentContext Id: '.$id);
        $child_dctx = new base_templateEngine_DocumentContext($id, $this->getLanguage(), $this, $template, '', $this->getMedium());
        return $child_dctx;
    }

}

?>